const Post = require("../models/postModel");
const User = require("../models/userModel");
const Apply   = require("../models/applyModel")
const { v4: uuid } = require('uuid');
const HttpError = require("../models/errorModel");
const sendMsg = async (userId, message) => {
  try {
    const user = await User.findById(userId)
    if (!user) {
      return ;
    }

    user.messages.push({text:message, created: Date.now()});
    //给用户列表添加一条新的消息，
    await user.save();
    //保存到数据库
  } catch (error) {
    //如果发生异常
    console.error("发送错误消息:", error);
    //就返回发送错误消息
    return next(new HttpError("服务器内部错误", 500));
  }//并返回一个表示服务器内部错误的响应
};

const createPost = async (req, res, next) => {
  try {
    let { title, contact, description, deadline, email, agree, wages } = req.body;
  //请求body参数中的标题、联系方式、描述、截止时间、邮箱、允许同意、工资信息
    console.log(req.body)
    if (!title || !description ) {
      //如果标题或描述中缺少字符或为空，
      return next(new HttpError("缺少必填的字段或文件", 422));
    }//则返回缺少必填的字段或文件

    const newPost = await Post.create({
      title,
      contact,
      email,
      deadline,
      description,
      agree,
      wages,
      creator: req.user.id,
    });
    //响应成功了将创建一个新的项目，包含标题、联系方式、描述、截止时间、邮箱、允许同意、工资、创建者的信息

    if (!newPost) {
      return next(new HttpError("无法创建项目", 422));
    }
  //如果创建新的项目失败将返回无法创建项目

    const currentUser = await User.findById(req.user.id);
    //首先从用户表通过ID查询数据，请求用户ID,
    if (!currentUser) {
      return next(new HttpError("未找到用户", 404));
    }
  //如果查询用户不存在，则返回未找到用户错误提示
    currentUser.posts += 1;
    await currentUser.save();
 //成功后用户的项目发布数增加1，然后保存用户数据
    res.status(201).json(newPost);
    //将新的项目数据返回给前端
  } catch (error) {
    //如果发生异常，
    console.error("创建项目错误:", error);
    //返回'创建项目错误'提示
    return next(new HttpError("服务器内部错误", 500));
  }//并返回一个表示服务器内部错误的响应
};

const getPosts = async (req, res, next) => {
  try {
    const posts = await Post.find({status:"approved"}).sort({ createdAt: -1 });
   //首先从项目数据库中找到状态为已通过的所有数据，并按创建时间倒序排序。
    res.status(200).json(posts);
    //将项目数据返回给前端
  } catch (error) {
    //如果发生异常，
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

const adminPosts = async (req, res, next) => {
  try {
    const id= req.user.id;
    //请求用户表里查询用户ID数据
    const user = await User.findById(id).select('-password');
    //等待用户表里查询出符合条件的ID对象，但不包含密码属性。
    if (!user) {
      //如果查看用户不存在
      return next(new HttpError("用户未找到", 404));
    }//则返回一个"用户未找到"
    if (process.env.ADMIN_MAIL === user.email) {
      //如果用户邮箱符合端口.env的管理员邮箱
      const posts = await Post.find({status:"applied"}).sort({ createdAt: -1 });
     //就从项目数据库里搜索所有状态为申请中，并按创建时间倒序排序
      res.status(200).json(posts);
      //将项目数据返回给前端
    } else {
      return next(new HttpError("非管理员", 403));
    }//如果不符合，则返回"非管理员"提示响应
  } catch (error) {
    //如果发生异常，
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

// 查看次数+1
const getView = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求项目参数中的项目ID
    const post = await Post.findById(postId);
    //根据项目ID表里查询指定项目数据，然后获得详细信息
    if (!post) {
      return next(new HttpError("找不到该项目", 404));
    }//如果查询项目不存在，则返回找不到该项目
    const newPost= await Post.findByIdAndUpdate(postId, { views: post.views + 1 });
    //根据查询项目ID更新项目查看次数，增加1次
    console.log('views + 1')
    //控制日志返回views+1
    res.status(200).json(newPost);
    //将更新后的项目返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

const getPost = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求项目参数中的项目ID
    const post = await Post.findById(postId);
    //根据项目ID表里查询指定项目数据，然后获得详细信息
    if (!post) {
      return next(new HttpError("找不到该项目", 404));
    }//如果查询项目不存在，则返回找不到该项目
    res.status(200).json(post);
    //返回posts列表给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

// 我创建的项目
const getUserPosts = async (req, res, next) => {
  try {
    const { id } = req.params;
    //请求参数中的ID
    const posts = await Post.find({ creator: id }).sort({ createdAt: -1 });
    //根据项目数据查询创建者的ID数据，并按照创建时间倒序排序
    res.status(200).json(posts);
    ////返回posts列表给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

// 我参与的项目
const getMyPosts = async (req, res, next) => {
  try {
    const { id } = req.params;
    //请求参数中的ID
    let posts = [];
    const applies = await Apply.find({userId:id});
    //根据userid查询所有申请记录，对于每一条申请记录，
    for await (const app of applies ){
      let post = await Post.findById(app.postId);
      //根据申请记录中的postid查询项目，补充申请状态到项目数据中
      let copy = {...post._doc, apply: app.status};
      //将复制的项目数据放到返回值列表
      posts.push(copy);
    }
    res.status(200).json(posts);
    //返回posts列表给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

const closePost = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求postid中的参数
    if (!postId) {
      return next(new HttpError("项目ID不可为空", 400));
    } //如果没有传参数，则返回错误项目ID不可为空。
    await Post.findByIdAndUpdate(postId, { status: 'closed'});
    //根据项目ID数据更改状态为关闭
    await Apply.updateMany({postId: postId}, {status: 'closed'});
    //根据项目ID更新所有申请表最新状态为关闭
    res.json(`Post ${postId} closed successfully`);
    //将项目状态关闭成功返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

const agreePost = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求postid中的参数
    if (!postId) {
      return next(new HttpError("项目ID不可为空", 400));
    }//如果没有传参数，则返回错误项目ID不可为空。
    const post=await Post.findByIdAndUpdate(postId, { status: 'approved'});
    //根据项目ID参数通过ID查找并更新状态为已通过
    sendMsg(post.creator,"您的申请的项目已通过，请注意查收");
    //根据项目状态给消息列表发送一条您的申请的项目已通过，请注意查收
    res.json(`Post ${postId} agree successfully`);
    //将项目状态已通过的数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

const rejectPost = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求postid中的参数
    if (!postId) {
      return next(new HttpError("项目ID不可为空", 400));
    }//如果没有传参数，则返回错误项目ID不可为空。
    const post=await Post.findByIdAndUpdate(postId, { status: 'failed'});
    //根据项目ID参数通过ID查找并更新状态为已拒绝
    sendMsg(post.creator, "您的申请项目已拒绝，请注意用词");
    //根据项目状态给消息列表发送一条您的申请项目已拒绝，请注意用词
    res.json(`Post ${postId} reject successfully`);
    //将项目状态已拒绝的数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

const likeUser = async (req, res, next) => {
  try {
    const id = req.params.id;
    //请求被评分的id中的参数
    const credit = req.params.credit;
    //请求credit中的参数
    const userId = req.user.id;
    //请求头部的用户登录消息，取出userid
    if (!userId) {
      return next(new HttpError("未经授权，请重新登录", 401));
    }//如果没有传用户ID参数，则返回错误 未经授权，请重新登录
    const user = await User.findById(id);
    //根据id查询被评分的用户数据
    if (!user) {
      return next(new HttpError("未找到用户", 404));
    }//如果没有传用户参数，则返回错误 未找到用户
    const alreadyLiked = user.likes.includes(userId);
   //检查用户数据的likes数据中是否包含了userid已经评分代表
    if (!alreadyLiked) {
      user.credits = ((user.credits * user.likes.length) + credit)/(user.likes.length + 1);
      user.likes.push(userId);
      //如果尚未评分，则计算新的评分；公式如上。(用户原评分 * 原评价数 + 新评分)除于总评价数
      await user.save();
      //最后，将用户信息保存到数据库中
    }
    res.status(200).json({
      isLiked: true,
      likes: user.likes,
      credits: user.credits
    });
    //将是否已评分，评分数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError("Server error", 404));
  }//返回一个表示服务器内部错误的响应
};

const apply = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求postid中的参数
    if (!postId) {
      return next(new HttpError("项目ID不可为空", 400));
    }//如果没有传到postid参数，则返回错误项目ID不可为空。
    const post = await Post.findById(postId);
    if (req.user.id === post.creator.toString()) {
      return next(new HttpError("项目申请失败", 422));
    }//如果是项目创建人自己则不能申请，返回错项目申请失败
    const userId = req.user.id;
    //请求Userid中的参数
    const applyExists = await Apply.findOne({postId, userId})
    //根据 postid和userid 查找申请表apply记录
    if (applyExists) {
      return next(new HttpError(`您已经申请了`, 422));
    }//如果查询到数据 说明已经申请过了。提示不要重复申请
    const newApply = await Apply.create({
      postId,
      userId,
      status: 'applied'
    });//否则 可以创建一条新的申请记录 保存到apply表
    if (!newApply) {
      return next(new HttpError("Failed to apply", 422));
    }//如果创建新的申请失败了，则返回错误申请失败
    sendMsg(post.creator, '您收到新的加入申请，请查看【我发布的项目】')
    //给项目的创建人发送消息，发送一条您收新的加入申请，请查看【我发布的项目】
    const applies = await Apply.find({postId}).sort({ updatedAt: -1 });
    //根据申请表数据查询创建者的ID数据，并按照更新时间倒序排序
    await Post.findByIdAndUpdate(postId, { applies: applies.length });
    //根据id更新项目的申请数
    res.status(200).json(newApply);
    //将是新的申请数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

// 查看申请状态
const applied = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求postid的参数中
    const userId = req.user.id;
    //请求userid的参数中
    let applies = await Apply.findOne({postId, userId}).sort({ updatedAt: -1 });
    //根据 postid和userid 查找申请记录，并按照更新时间倒序排序
    if(!applies) {
      applies = {'status':'init'}
    }//如果申请状态是初始数据，则保留原样
    res.status(200).json(applies);
    //将申请项目数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

const rejectApply = async (req, res, next) => {
  try {
    const applyId = req.params.id;
    //请求applyid的参数中
    if (!applyId) {
      return next(new HttpError("项目ID不可为空", 400));
    }//如果没有传到applyid参数，则返回错误项目ID不可为空
    await Apply.findByIdAndUpdate(applyId, { status: 'failed'});
    //根据applyid查找申请状态为失败记录
    res.json(`Apply ${applyId} reject successfully`);
    //将申请状态已拒绝的数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};


const agreeApply = async (req, res, next) => {
  try {
    const applyId = req.params.id;
    //请求applyid的参数中
    if (!applyId) {
      return next(new HttpError("项目ID不可为空", 400));
    }//如果没有传到applyid参数，则返回错误项目ID不可为空
    let apply = await Apply.findByIdAndUpdate(applyId, { status: 'approved'});
    //根据applyid找到并更新申请状态为已通过记录
    sendMsg(apply.userId, '您的申请已通过，请查看【我参与的项目】')
    //给项目的申请人发送消息，发送一条您的申请通过，请查看【我参与的项目】
    res.json(`Apply ${applyId} agree successfully`);
    //将申请状态已同意的数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));ß
  }//返回一个表示服务器内部错误的响应
};

const getApplies = async (req, res, next) => {
  try {
    const postId = req.params.id;
    //请求postid的参数中
    const applies = await Apply.find({postId}).sort({ updatedAt: -1 });
    //根据postid查找该项目的申请中记录，并按照更新时间倒序排序
    res.status(200).json(applies);
    //将申请的数据返回给前端
  } catch (error) {
    //如果发生异常
    return next(new HttpError(error));
  }//返回一个表示服务器内部错误的响应
};

module.exports = {
  createPost,
  getPosts,
  adminPosts,
  getPost,
  getView,
  getUserPosts,
  getMyPosts,
  closePost,
  agreePost,
  rejectPost,
  agreeApply,
  rejectApply,
  likeUser,
  apply,
  applied,
  getApplies
};
